﻿/*
 * @Author Wujiajun
 * @Data 2021/2/20
 * @Description 场景管理器
 * 激活场景，叠加场景的切换，叠加加载场景，卸载场景，加载场景
 * 
 */

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement; //需要使用到的命名空间SceneManagement

public class MySceneManager : MonoBehaviour
{
    private string m_SceneLogicName = "[SceneLogicName]";

    private void Awake()
    {
        SceneManager.activeSceneChanged += OnActiveSceneChanged; //切换场景回调方法~
    }

    /// <summary>
    /// 2个场景之间的切换
    /// </summary>
    /// <param name="inActiveScene">需要关闭的场景参数</param>
    /// <param name="activeScene">需要激活的场景参数</param>
    private void OnActiveSceneChanged(Scene inActiveScene, Scene activeScene)
    {
        if (!inActiveScene.isLoaded || !activeScene.isLoaded)
            return;
        SceneLogicBehaviour sceneLogic1 = GetSceneLogic(inActiveScene);
        SceneLogicBehaviour sceneLogic2 = GetSceneLogic(activeScene);
        sceneLogic1?.OnSceneInActive();
        sceneLogic2?.OnSceneActive();
    }

    /// <summary>
    /// 1.先对内封装的真正的读取场景的功能
    /// </summary>
    /// <param name="sceneName">场景名称</param>
    /// <param name="luaName">lua名称</param>
    /// <param name="mode">读取场景类型</param>
    /// <returns></returns>
    private IEnumerator StartLoadScene(string sceneName,string luaName ,LoadSceneMode mode)
    {
        if (IsLoadedScene(sceneName)) //先判断是否已经加载场景了
            yield break;

        AsyncOperation async = SceneManager.LoadSceneAsync(sceneName,mode); //异步加载场景
        async.allowSceneActivation = true; //允许在场景准备就绪后立即激活场景。
        yield return async; //等待完成
       
        Scene scene = SceneManager.GetSceneByName(sceneName); //只能通过场景名称来获取场景，上面的方法无法获取场景
        GameObject go = new GameObject(m_SceneLogicName); 
        SceneManager.MoveGameObjectToScene(go, scene); //将挂载场景管理器的对象移动到这个场景的对象上
        SceneLogicBehaviour sceneLogic = go.AddComponent<SceneLogicBehaviour>(); //再挂载场景逻辑
        sceneLogic.SceneName = sceneName;
        sceneLogic.Init(luaName);
        sceneLogic.OnSceneEnter();
    }

    //卸载场景
    private IEnumerator UnLoadSceneAsync(string sceneName)
    {
        Scene scene = SceneManager.GetSceneByName(sceneName);
        if (!scene.isLoaded) //未被加载
        {
            Debug.LogError("scene not isloaded");
            yield break;
        }
        SceneLogicBehaviour sceneLogic = GetSceneLogic(scene); //先判断有没有这个场景逻辑
        sceneLogic?.OnSceneQuit(); //调用Lua方法
        AsyncOperation async = SceneManager.UnloadSceneAsync(sceneName); //异步卸载场景
        yield return async;
    }

    //获取场景逻辑Lua的方法
    private SceneLogicBehaviour GetSceneLogic(Scene scene)
    {
        GameObject[] goes=scene.GetRootGameObjects();
        for (int i = 0; i < goes.Length; i++)
        {
            if (string.Compare(goes[i].name, m_SceneLogicName, StringComparison.CurrentCulture) == 0)
            {
                SceneLogicBehaviour sceneLogic = goes[i].GetComponent<SceneLogicBehaviour>();
                return sceneLogic;
            }
        }
        return null;
    }

    /// <summary>
    /// 确认是否已经加载过场景
    /// </summary>
    /// <param name="sceneName">场景名称参数~</param>
    /// <returns></returns>
    private bool IsLoadedScene(string sceneName)
    {
        Scene scene = SceneManager.GetSceneByName(sceneName);
        return scene.isLoaded;
    }


    #region 对外接口

    //场景激活
    public void SetSceneActive(string sceneName)
    {
        Scene scene = SceneManager.GetSceneByName(sceneName);
        SceneManager.SetActiveScene(scene);
    }

    //叠加场景加载
    public void LoadScene(string sceneName, string luaName)
    {
        Manager.ResourceManager.LoadScene(sceneName, (UnityEngine.Object obj) =>
        {
            StartCoroutine(StartLoadScene(sceneName, luaName, LoadSceneMode.Additive)); //mode是叠加additive
        });
    }

    //单个场景切换
    public void ChangeScene(string sceneName, string luaName)
    {
        Manager.ResourceManager.LoadScene(sceneName, (UnityEngine.Object obj) =>
        {
            StartCoroutine(StartLoadScene(sceneName, luaName, LoadSceneMode.Single));
        });
    }

    //卸载场景
    public void UnLoadScene(string sceneName)
    {
        StartCoroutine(UnLoadSceneAsync(sceneName));
    }

    #endregion
}
